#include "testing/testing.hpp"

#include "tbcore/base/buffer-internal.hpp"
#include "tbcore/base/memory_buffer.hpp"

TB_NAMESPACE_BEGIN

TEST(BufferTest, BasicTest) {
	//reserve
	{
		MemoryBuffer buff;
		ASSERT_EQ(buff.Size(), 0);

		buff.Reserve(1024);
		ASSERT_EQ(buff.impl_->blobs_.size(), 1);

		buff.Reserve(1025);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);

		buff.Reserve(2048);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);

		buff.Reserve(2049);
		ASSERT_EQ(buff.impl_->blobs_.size(), 3);
	}

	char tmp[2048];

	//basic write
	{
		MemoryBuffer buff;

		buff.WriteBytes(tmp, 1024);
		ASSERT_EQ(buff.Size(), 1024);
		ASSERT_EQ(buff.impl_->blobs_.size(), 1);
		ASSERT_EQ(buff.ReadIndex(), 0);
		ASSERT_EQ(buff.WriteIndex(), 1024);

		buff.WriteBytes(tmp, 1);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);
		ASSERT_EQ(buff.ReadIndex(), 0);
		ASSERT_EQ(buff.WriteIndex(), 1025);

		Blob b1 = buff.ReadBytes(1024);
		ASSERT_EQ(b1.size(), 1024);
		ASSERT_EQ(buff.ReadIndex(), 1024);
		
		Blob b2 = buff.ReadBytes(1024);
		ASSERT_EQ(b2.size(), 0);
		ASSERT_EQ(buff.ReadIndex(), 1024);

		buff.SeekRead(0);
		ASSERT_EQ(buff.ReadIndex(), 0);
		ASSERT_EQ(buff.WriteIndex(), 1025);

		buff.SkipRead(1024);
		ASSERT_EQ(buff.ReadIndex(), 1024);

		buff.SkipRead(1);
		ASSERT_EQ(buff.ReadIndex(), 1025);
	}

	//seek write
	{
		MemoryBuffer buff;

		buff.SeekWrite(1023);
		buff.WriteBytes(tmp, 2);
		ASSERT_EQ(buff.WriteIndex(), 1025);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);
	}

	//write value
	{
		MemoryBuffer buff;

		buff.WriteBytes(tmp, 1);
		ASSERT_EQ(buff.WriteIndex(), 1);
		ASSERT_EQ(buff.impl_->blobs_.size(), 1);

		buff.WriteValue(tmp, 1024);
		ASSERT_EQ(buff.WriteIndex(), 1025);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);
		ASSERT_EQ(buff.impl_->blobs_.front().size(), 1);
		ASSERT_EQ(buff.impl_->blobs_.back().size(), 1024);
		ASSERT_EQ(buff.impl_->writeOffset_, 1024);
	}

	//basic read
	{
		MemoryBuffer buff;

		buff.WriteBytes(tmp, 1025);
		ASSERT_EQ(buff.WriteIndex(), 1025);
		ASSERT_EQ(buff.impl_->blobs_.size(), 2);

		tuple<const char*, uint32> d = buff.PeekBytes(1024);
		ASSERT_EQ(get<1>(d), 1024);
		ASSERT_EQ(buff.ReadIndex(), 0);

		const char* d1 = buff.ReadValue(1025);
		ASSERT_TRUE(!d1);
		ASSERT_EQ(buff.ReadIndex(), 0);

		const char* d2 = buff.ReadValue(1024);
		ASSERT_TRUE(d2 != nullptr);
		ASSERT_EQ(buff.ReadIndex(), 1024);
	}

	//shrink
	{
		MemoryBuffer buff;
		
		buff.WriteBytes(tmp, 1024);
		buff.WriteBytes(tmp, 1024);
		ASSERT_EQ(buff.WriteIndex(), 2048);

		buff.SkipRead(1024);
		ASSERT_EQ(buff.impl_->readOffset_, 1024);
		ASSERT_EQ(buff.impl_->readingBlob_, 1);

		buff.Shrink();
		ASSERT_EQ(buff.impl_->readOffset_, 0);
		ASSERT_EQ(buff.impl_->readingBlob_, 1);
		ASSERT_EQ(buff.impl_->writingBlob_, 1);
		ASSERT_EQ(buff.impl_->writeOffset_, 1024);
	}

	//merge
	{
		MemoryBuffer buff;

		buff.WriteBytes(tmp, 1024);
		buff.WriteBytes(tmp, 1024);
		buff.WriteBytes(tmp, 1);
		ASSERT_EQ(buff.WriteIndex(), 2049);

		Blob m = buff.Merge();
		ASSERT_EQ(m.size(), 2049);
	}
}

TEST(BufferTest, SequenceWriteTest) {
	uint8 tmp[1024];

	for (uint32 i = 0; i < 1024; ++i) {
		tmp[i] = i % 10;
	}

	MemoryBuffer buff;
	for (uint32 i = 0; i < 1000; ++i) {
		buff.WriteValue((char*)tmp, 1);
		buff.WriteValue((char*)tmp, 4);
		if (buff.impl_->writeOffset_ > 1024) {
			int a = 0;
		}
	}
}

TB_NAMESPACE_END